package io.hellsinger.vortex.ui.screen.storage.media

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams.MATCH_PARENT
import android.widget.ImageView
import io.hellsinger.navigation.screen.ScreenController
import io.hellsinger.viewmodel.BitViewModel
import io.hellsinger.vortex.bit.Bits.Companion.hasFlag
import io.hellsinger.vortex.data.model.PathItem
import io.hellsinger.vortex.di.createViewModel
import io.hellsinger.vortex.ui.component.LoadingView
import io.hellsinger.vortex.ui.dsl.frame
import io.hellsinger.vortex.ui.dsl.frameParams
import io.hellsinger.vortex.ui.dsl.image
import io.hellsinger.vortex.ui.dsl.loading
import io.hellsinger.vortex.ui.dsl.params

class StorageMediaEntryScreenController(
    private val context: Context,
) : ScreenController<PathItem>(),
    BitViewModel.UiStateUpdateCollector<UiState> {
    private var viewModel: StorageMediaViewModel? = null

    private var animator: ValueAnimator? = null

    private var root: FrameLayout? = null
    private var loading: LoadingView? = null
    private var image: ImageView? = null

    override fun onBackActivatedImpl(): Boolean = false

    override fun onCreateViewImpl(context: Context): View {
        root =
            frame(context) {
                params(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
                image =
                    image {
                        frameParams(MATCH_PARENT, MATCH_PARENT)
                    }

                loading =
                    loading {
                        visibility = GONE
                        frameParams(MATCH_PARENT, MATCH_PARENT)
                    }
            }
        return root!!
    }

    override fun onPrepareImpl() {
        if (viewModel == null) {
            viewModel = context.createViewModel()
        }
        viewModel?.collectUiState(this)
        args?.let { item -> viewModel?.load(item) }
    }

    override fun onFocusImpl() {
    }

    override fun onHideImpl() {
        viewModel?.cancelCollectUiState()
    }

    override fun onDestroyImpl() {
        animator?.cancel()
        root?.removeAllViews()
        loading = null
        image = null
        root = null
        viewModel?.onDestroy()
        viewModel = null
    }

    override fun onSaveImpl(
        buffer: Bundle,
        prefix: String,
    ): Boolean = false

    override fun onRestoreImpl(
        buffer: Bundle,
        prefix: String,
    ): Boolean = false

    override suspend fun emit(
        event: Int,
        state: UiState,
    ) {
        if (event hasFlag StorageMediaViewModel.UPDATE_LOADING_EVENT) {
            navigateLoading()
        }

        if (event hasFlag StorageMediaViewModel.UPDATE_IMAGE_LOADED_EVENT) {
            image?.setImageBitmap(state.image)
            navigateImage()
        }
    }

    private fun navigateLoading() {
        if (loading?.visibility == VISIBLE) return
        animator?.cancel()
        createSwitchAnimator()

        animator?.addUpdateListener { anim ->
            if (image?.visibility == VISIBLE) image?.alpha = 1F - anim.animatedFraction
            loading?.alpha = anim.animatedFraction
        }

        animator?.addListener(
            object : AnimatorListenerAdapter() {
                override fun onAnimationCancel(animation: Animator) {
                    loading?.alpha = 1F
                    loading?.visibility = VISIBLE
                    image?.visibility = GONE
                    animator = null
                }

                override fun onAnimationStart(animation: Animator) {
                    loading?.visibility = GONE
                }

                override fun onAnimationEnd(animation: Animator) {
                    loading?.alpha = 1F
                    loading?.visibility = VISIBLE
                    image?.visibility = GONE
                    animator = null
                }
            },
        )

        animator?.start()
    }

    private fun navigateImage() {
        if (image?.visibility == VISIBLE) return
        animator?.cancel()
        createSwitchAnimator()

        animator?.addUpdateListener { anim ->
            if (loading?.visibility == VISIBLE) loading?.alpha = 1F - anim.animatedFraction
            image?.alpha = anim.animatedFraction
        }

        animator?.addListener(
            object : AnimatorListenerAdapter() {
                override fun onAnimationCancel(animation: Animator) {
                    image?.alpha = 1F
                    image?.visibility = VISIBLE
                    loading?.visibility = GONE
                    animator = null
                }

                override fun onAnimationStart(animation: Animator) {
                    image?.visibility = GONE
                }

                override fun onAnimationEnd(animation: Animator) {
                    image?.alpha = 1F
                    image?.visibility = VISIBLE
                    loading?.visibility = GONE
                    animator = null
                }
            },
        )

        animator?.start()
    }

    private fun createSwitchAnimator(duration: Long = 150L): ValueAnimator {
        if (animator != null) return animator!!

        val animator = ValueAnimator.ofFloat(0F, 1F)
        animator.duration = duration
        this.animator = animator
        return animator
    }
}
